This chapter describes changes made to the Enterprise Objects Framework (EOF) between release 3.0 and 4.5. It describes changes made to existing features and describes new features you may want to start using in your applications.
Note: To synchronize the version numbers of WebObjects and EOF, the version number of EOF was increased from 3.0 in the last release to 4.5 in this release. |
In EOF 4.5, EOModeler supports synchronization of a database schema with the current state of a model.
Note: The Informix and ODBC adaptors do not provide schema synchronization support. |
To initiate the process of synchronizing a model and schema, select "Synchronize Schema" from the Model menu. Note that before synchronizing, you need to save your model. Because the operation cannot be undone, the "Synchronize Schema" menu item is only enabled when the model has no unsaved changes.
After starting the synchroniztion process, EOModeler reverse engineers the database's schema and assembles the adaptor operations necessary to synchronize it with the model. These operations are presented to the user for confirmation before execution.
For example, if you add simple attributes (attributes representing database columns) to an entity, schema synchronization adds the columns to the underlying table. Similarly new columns or tables created in the database can be selected for incorporation into the model. External type changes for attributes and the renaming of columns and tables are also supported.
EOModeler makes use of the schema synchronization API to synchronize your database with your model. You don't need to use the API yourself unless you're implementing the API for a custom adaptor.
If you do need to use or implement this API (very unlikely), see the related documentation in the following class and interface/protocol specifications:
WebObjects 4.5 introduces event logging. The goal for this feature is to allow the measurement of how long certain operations in EOF and WebObjects take. Measurements allow you to profile an application and optimize its execution time. For this, the EOF and WebObjects frameworks instrument key portions of their code to measure the elapsed time of functions and methods.
Note: The event logging feature, related classes, and related API are not available in the com.apple.client packages. Therefore, you can't time the client side of a Java Client application. |
To support this feature, EOF adds two new classes: EOEvent and EOEventCenter. An EOEvent keeps information (such as duration) about a logged event, and EOEventCenter manages the events. EOEvent is an abstract class whose subclasses are responsible for defining the events they track. For example, there are (private) subclasses for Sybase adaptor events, editing context events, WOApplication events, and so on.
To enable event logging in an application, simply open the WOEventSetup page as described in "WOEventSetup page" and enable logging for the event classes you want to see.
In addition to the framework support, the WOExtensions framework provides components for using the feature. WOEventSetup is a page you use to configure event logging, and WOEventDisplay is a page the displays event information. Both pages can be accessed in any WebObjects 4.5 application with a direct action, as described in the following sections.
The page used to set up the logging properties is accessed through a direct action named "WOEventSetup". So for example, you can access the WOEventSetup page for an application named "MyApp" with a URL such as the following:
http://myhost:aPort/cgi-bin/WebObjects/MyApp.woa/wa/WOEventSetup
On the WOEventSetup page, you can see all families of events that are registered for the application. Since the event classes are registered dynamically as the program executes, it is a good idea to "warm up" an application before accessing WOEventSetup.
The page lists the registered event classes, their subcategories,
and a description of the kinds of events that can be logged. For
instance, the EOEditingContext event class logs events for the saveChanges
and objectsWithFetchSpecification:
methods.
Logging for each class can be enabled and disabled with the corresponding
check box; it isn't possible to disable individual subcategories
of an event class.
The page that displays collected events, WOEventDisplay, is also accessed through a direct action. For example, you can access the WOEventSetup page for an application named "MyApp" with a URL such as the following:
http://myhost:aPort/cgi-bin/WebObjects/MyApp.woa/wa/WOEventDisplay
On this page, you can view events in four different ways:
In any of these displays, if an event or event group has subevents, it can be expanded by clicking the hyperlink or triangle image.
Each view orders events by duration (in milliseconds) from the longest to the shortest. Aggregation reduces rounding errors, which are a maximum of 1ms per event. In other words, an aggregate event consisting of ten events has at most 1ms deviation from the actual run time; however, manually adding ten individual events as displayed in the table might have up to a 10ms deviation. Therefore, any displayed sum is always more accurate than adding up the durations of individual events. Also note that the sub-events of an event branch doesn't necessarily add up to the duration of the branch event-the branch event's duration might be larger. This because the parent event generally consists of more than just calling the methods causing the sub-events.
The event system provides three defaults for configuring its behavior:
To define and log custom events, you create an event class, define the event's categories and subcategories, register the event class with the WOEvent center, and instrument the portions of code you want to log. This section describes these steps.
To create a custom event:
{ EOEventGroupName = "MyAdaptor Event"; connect = "Connect"; openChannel = "Open Channel"; evaluateExpression = "Evaluate Expression"; fetchRow = "Fetch Row"; commitTransaction = "Commit Transaction"; }
connect
, openChannel
,
and so on) are the names of the events MyAdaptorEvent logs.initialize
method
of the class whose code you're instrumenting-MyAdaptor in this
example.static Class MyAdaptorEventLoggingClass = Nil; static NSString *connectEvent = @"connect"; static NSString *openChannelEvent = @"openChannel"; static NSString *evaluateExpressionEvent = @"evaluateExpression"; static NSString *fetchRowEvent = @"fetchRow"; static NSString *commitTransactionEvent = @"commitTransaction"; + (void)initialize { [EOEventCenter registerEventClass:[MyAdaptorEvent class] classPointer:&MyAdaptorEventLoggingClass]; }
MyAdaptorEvent *event=nil; // Setup and start logging if(MyAdaptorEventLoggingClass) { event = EONewEventOfClass(MyAdaptorEventLoggingClass, connectEvent); EOMarkStartOfEvent(event, nil); } // Code to be timed goes here. // Finish logging. if(event) { EOMarkEndOfEvent(event);
Three new classes and one interface have been added to support event logging. They are:
For more information, see the corresponding class or interface specifications.
Note: These classes and interfaces aren't available in the com.apple.client.eocontrol package. |
EOF 4.5 introduces a new technique for sharing read-only enterprise objects. The new subclass of EOEditingContext, EOSharedEditingContext, defines a mechanism that allows editing contexts to share enterprise objects for reading. This mechanism can reduce both the number of fetches an application makes and the amount of redundant data it requires.
As an example, consider the FeeType entity in the samle Rentals model that ships with EOF 4.5. A FeeType enterprise objects describes a type of fee that a video store can charge its customers-"Rental" and "Late", are the two FeeTypes in the sample database. It is very uncommon to add or remove FeeTypes, and it's perhaps even more uncommon to modify an existing FeeType (to rename it, for example). For the most part, FeeTypes are read-only.
With 4.5, you can fetch read-only objects such as FeeTypes into a shared editing context once, when an application starts, and all the application's sessions can share those objects. For example, objects in any session can create relationships to the shared FeeType objects even though the FeeTypes are in a different editing context from the source objects. Using previous releases, you would have to make local copies of the read-only FeeTypes in each of the editing contexts that use them.
Note: Support for shared editing contexts is not implemented in the com.apple.client packages. Therefore, shared editing contexts are not available in the client side of a Java Client application. |
The idea behind shared editing contexts is to load read-only (or read-mostly) objects into a central context that all sessions have transparent access to. It works like this.
objectForGlobalID
and faultForGlobalID
look
for an object in the shared editing context when a standard editing
context doesn't find the object locally. If the methods finds
the object in the shared editing context, they return the shared
object as they would if the object were local.To allow object sharing to work, EOF makes the following assumptions:
The following sections describe why these assumptions are necessary and how they are enforced.
If you could update a shared object, all of an application's users would see the changes immediately since all sessions share the exact same object. This behavior is undesirable. You only want users to see committed changes to objects. For example, suppose you make a change to a shared object in a web application, but you haven't yet saved it to the database. The changes are written to the object as soon as the request-response loop begins, and every other web user sees the change you made, even if you undo them later or make further changes before saving.
For this reason EOF enforces the read-only quality of shared
objects. Shared objects can't be inserted, updated, or deleted
in a shared editing context the same way that normal enterprise
objects can be inserted, updated, or deleted when they're in a
standard editing context. EOSharedEditingContext overrides EOEditingContext
methods that mutate data (takeValueForKey
, saveChanges
, deleteObject
,
and insertObject
for example) to raise exceptions.
Correspondingly, methods that report on changes in a shared editing
context return either null
/nil
or
an empty array.
It would also be undesirable if you could delete a shared object. In Objective-C, it would be bad if a shared object were released while objects in standard editing contexts had relationships to it. Objects in a shared editing context are always retained. You are guaranteed that no object in a shared editing context will be destroyed while the application is running (a shared object can become invalid, but it won't go away).
EOF uses object uniquing to ensure that a single editing context never has more than one object with the same global ID. Because every standard editing context has access to the objects in a shared editing context as if the objects were local, none of a shared editing context's objects can have the same global ID as any object in any standard editing context.
EOF does most of the work for you. A shared editing context sends out notifications when it initializes new objects. Standard editing contexts listen for these notifications and raise exceptions if they have local objects with the same global ID as the new shared object. However, you have to take some precautions not to fetch into a shared editing context objects that have already been fetched into a standard editing context:
EOModeler has a new entity inspector for specifying the objects you want to fetch into a shared editing context when an application starts. To use it, select the entity whose objects you want to share, and open the Shared Objects Inspector.
To share all the entity's objects, select "Share all objects." If the entity has an unqualified fetch specification, that fetch specification is selected. Otherwise, EOModeler creates an unqualified fetch specification and selects it.
To share only some objects, define fetch specifications that select the objects you want to share. In the Shared Objects Inspector, select "Share objects fetched with" and select your fetch specifications.
You can also prefetch relationships into the shared editing context. For example, suppose that Product has a relationship to ProductPlatforms and that both entities should be shared. You can create a Product fetch specification that has a hint to prefetch the Product's ProductPlatforms relationship. Using this fetch specification to fetch Products into the shared editing context also causes ProductPlatforms to be loaded into the shared editing context.
Shared editing contexts maintain dictionaries of all the objects they have fetched, both by entity name and by the fetch specification name they were retrieved with. This makes it easy to use shared objects for populating user interface controls. The two methods for accessing these dictionaries are:
objectsByEntityName objectsByEntityNameAndFetchSpecificationName
These two methods make it easy to use key-value coding and key paths to bind data to WebObjects elements directly in a WebObjects .wod file.
For example: Say you have a model with the entity "Products"
and an attribute called "isDiscontinued", which indicates whether
an item is unavailable. You could set up a fetch specification in
EOModeler named "regularProducts" that fetches only objects
that are available (the qualifier would specify that "isDiscontinued
= 0"). To use the returned set of "regular products" in
a WebObjects page, create a user interface control (such as a WOPopup
or WOBrowser), and set its list
attribute
like this:
list = session.defaultSharedEditingContext.objectsByEntityNameAndFetchSpecificationName.Products.regularProducts
The user interface control's list is automatically filled with data from shared objects.
Generally shared objects are read-mostly. For example, an application could provide an administration mode that allows administrative users to insert, update, and delete otherwise read-only shared objects. You can still use a shared editing context in such an application, but you have to write special code. Since insertions, updates, and deletions of shared objects are typically very infrequent, the performance benefit of sharing objects can still be significant.
To insert new objects, create and insert a new object in a standard editing context. Once you do this, you need to fetch the new object into the shared editing context as described in "Refreshing the Shared Editing Context" .
Updating and deleting them is a little trickier. To modify shared objects, you need to disable object sharing for a particular editing context, as follows:
mySession.defaultEditingContext().setSharedEditingContext(null); // Java [[mySession defaultEditingContext] setSharedEditingContext:nil]; // ObjC
A session that does this doesn't have access to shared objects
and can explicitly fetch objects that would otherwise be shared.
After fetching the objects, they are local, and you can update or
delete them. When you save the changes, the shared editing context
receives ObjectsChangedInStoreNotifications. In response to the
notifications, the shared editing context refaults updated objects
and removes deleted objects from its objectsByEntityName
and objectsByEntityNameAndFetchSpecificationName
dictionaries.
Note: Deleted objects remain in the shared editing context so that Objective-C objects having relationships to them won't be left with dangling pointers. |
You might want to refresh the shared editing context after
an administrative user inserts a new shared object or to periodically
synchronize with a database. To refresh a shared editing context,
use the method bindObjectsWithFetchSpecification
(Java)
or bindObjectsWithFetchSpecification:toName:
(Objective-C).
For example:
EOModelGroup modelGroup = EOModelGroup.defaultGroup(); EOSharedEditingContext sharedEC = EOSharedEditingContext.defaultSharedEditingContext(); EOFetchSpecification fs = modelGroup.fetchSpecificationNamed("regularProducts", "Product"); if (fs == null) { System.out.println("Couldn't get regularProducts fetch specification."); } else { sharedEC.bindObjectsWithFetchSpecification(fs, "regularProducts"); }
This has the effect of refetching all the shared objects and
binding them to the objectsByEntityName
and objectsByEntityNameAndFetchSpecificationName
dictionaries.
Initializing a shared editing context does increase the amount
of time it takes for an application to start up. During development
when you starting your application frequently, the additional start
up time can become a nuisance. To make debugging passes quicker,
you can essentially disable object sharing using the static method setSharedObjectLoadingEnabled
(or
the equivalent class method in Objective-C).
This method specifies whether EOF looks for shared fetch specifications when it loads models. While a shared editing context can still be created and referenced, it won't contain any objects unless you programmatically fetch them into it. The advantage of disabling shared object loading is that the application starts up more quickly.
Using shared editing contexts can have the following positive performance impact on your application:
However, there are potentially negative performance effects as well. They are:
WebObjects applications take care of most multithreading issues for you. This is also the case with applications that use shared editing contexts. Here are the basics of how EOF locks shared editing contexts:
lock
method
is called, it also obtains a reader lock for its shared editing
context.From a WebObjects perspective, everything works automatically as long as you interact with a shared editing context from within the context of a session. This is because when a web session awakes, it locks its editing context, which reader-locks the shared editing context. If you need to interact with the shared editing context outside the context of a session, you should access it through a locked EOEditingContext.
If you invoke methods on a shared editing context directly,
you must obey a strict lock ordering protocol to avoid deadlocks
and unsafe multithreaded access. If you directly invoke any method
besides objectsWithFetchSpecification
, objectForGlobalID
,
or faultForGlobalID
on a shared editing
context, you need to take the a reader or writer lock yourself before
calling the method.
A new subclass of EOEditingContext, EOSharedEditingContext, has been added to support object sharing. For more information on this class, see the corresponding class specification.
Note: With this release of EOF, there is a subclass of EOEditingContext for the first time. You might have to adjust your code if you ever assume than an editing context is always an instance of EOEditingContext. |
Note: Support for shared editing contexts is not implemented in the com.apple.client packages. |
Additionally, new API has been added to existing classes as summarized in the following tables.
New or Changed API | Description |
setSharedObjectLoadingEnabled (Java)setSharedObjectLoadingEnabled: (Objective-C) |
A static/class method that sets according to the specified
flag whether or not to automatically load enterprise objects into
the default shared editing context when a database context loads
a model. The default is true /YES (the
database automatically loads shared objects). |
isSharedObjectLoadingEnabled |
A static/class method that returns true /YES if
database contexts automatically load enterprise objects into the default
shared editing context when database contexts load models, false /NO otherwise. |
New or Changed API | Description |
setSharedObjectFetchSpecificationsByName (Java)setSharedObjectFetchSpecificationsByName: (Objective-C) |
Sets the fetch specifications used to load objects into a shared editing context to the fetch specifications identified by name in the specified array. |
sharedObjectFetchSpecificationNames |
Returns an array of strings, which are the names of the fetch specifications used to load objects into a shared editing context. |
addSharedObjectFetchSpecificationByName (Java)addSharedObjectFetchSpecificationByName: (Objective-C) |
Adds the fetch specification identified by the specified name to the set of fetch specifications used to load objects into a shared editing context. |
removeSharedObjectFetchSpecificationByName (Java)removeSharedObjectFetchSpecificationByName: (Objective-C) |
Removes the fetch specification identified by the specified name from the set of fetch specifications used to load objects into a shared editing context. |
New or Changed API | Description |
entitiesWithSharedObjects |
Returns an array of entities that have objects to load into a shared editing context. |
New or Changed API | Description |
entitiesWithSharedObjects |
Returns an array of entities that have objects to load into a shared editing context. |
New or Changed API | Description |
setSharedEditingContext (Java)setSharedEditingContext: (Objective-C) |
Sets the receiver's shared editing context. If the
receiver is listening for (EO)DefaultSharedEditingContextWasInitializedNotification ,
it removes itself as an observer. By default, the shared editing context is null /nil but
is set when an (EO)DefaultSharedEditingContextWasInitializedNotification is
posted.Changing the shared editing context to null /nil allows the
receiver to obtain private, editable copies of objects that would
otherwise be shared. If both the receiver and the specified shared
editing context have registered objects, the objects of both contexts
are compared to verify that the objects are unique. If the objects
are not unique, an exception is raised by the editing context. |
sharedEditingContext |
Returns the shared editing context used by the receiver. |
EOF 4.5 adds a new option for creating custom enterprise objects: rather than creating a subclass of EOCustomObject (Java) or NSObject (Objective-C), you can now subclass EOGenericRecord.
This feature is most significant in applications that use the Java bridge. By default, a subclass of EOGenericRecord stores its properties in a dictionary on the Objective-C side of the bridge instead of in individual instance variables on the Java side. This allows EOF to access enterprise object properties with many fewer trips across the bridge, which reduces memory usage and improves performance.
More specifically, subclassing EOGenericRecord provides the following advantages over subclassing EOCustomObject (Java):
valueForKey
) resulted in
a bridged method invocation and possibly the creation of a new object.
Because EOGenericRecord provides the storage for an enterprise object's
values, the values don't need to cross the bridge during a fetch.
This results in a dramatic performance improvement in EOKeyValueCoding-bound
operations such as fetching, snapshotting, and validation.createInstanceWithEditingContext
method
in the same way that EOGenericRecord must. If it isn't, the resulting
instance won't be properly initialized.Given all the advantages of subclassing EOGenericRecord, you might wonder if there's ever a reason to subclass EOCustomObject. Subclassing EOGenericRecord usually yields better performance. Even if it doesn't yield better performance, you can design it to be at least as fast and to have the same level of functionality as a subclass of EOCustomObject by storing properties in instance variables. Therefore, you really don't ever need to subclass EOCustomObject.
A subclass of EOGenericRecord can take three approaches to storing property values:
Generally the first approach is the best because it reduces the number of trips across the Java bridge, improving performance and reducing memory usage. Enterprise objects are accessed from Objective-C much more frequently than from Java. A typical enterprise object is populated from Objective-C when it's fetched from the database, snapshotted from Objective-C each time the object is changed, and accessed from Objective-C to provide values for bindings in WebObjects components.
On the other hand, access from Java is typically limited to custom validation (implemented in the enterprise object class) and to accesses by other enterprise objects to obtain property values explicitly (for example, to check the department budget before validating a new salary).
The second approach might be appropriate if your application accesses and manipulates enterprise objects from Java quite frequently, however this case is probably rare.
Note: When
you create an instance variable for an EOGenericRecord subclass,
ensure that the accessor methods read and write the instance variable
instead of invoking valueForKey and takeValueForKey ,
which is what the implementations do if the code is generated by
EOModeler. |
The third approach is to create instance variables for some of your enterprise object's properties and leave the rest in the EOGenericRecord dictionary. This approach is the most difficult to maintain, because the implementation of accessor methods depends on the way the property is stored.
EOModeler has been updated with templates that take advantage of this feature, so new enterprise object classes are automatically subclasses of EOGenericRecord. To re-parent existing business objects, perform the following steps in your source files:
storedValueForKey
,
such as:public NSGregorianDate dateReleased() { return (NSGregorianDate)storedValueForKey("dateReleased"); }
In lieu of (or in addition to) adding custom accessors, it might be convenient to add and use String constants for an enterprise object class's keys, as shown in the following:
public class Movie extends EOGenericRecord { public static final String Title = "title"; public static final String DateReleased = "dateReleased"; public static final String Studio = "studio"; public NSGregorianDate dateReleased() { return (NSGregorianDate)storedValueForKey(DateReleased); } }
EOF uses faults as stand-ins for objects whose data has not yet been fetched. Although fault creation is much faster than fetching, fault instantiation still takes time. To improve performance, EOF 4.5 has the ability to use deferred faults (which are more efficient) for enterprise object classes that enable the feature.
In an object whose class enables deferred faulting, the object's relationships are initially set to deferred faults. For a particular relationship, a single deferred fault is shared between all instances of an enterprise object class. This sharing of deferred faults can significantly reduce the number of faults that need to be created, and usually reduces the overhead of fault creation during a fetch.
For example, consider a Movie class with a studio
relationship.
Assuming the worst case in which each movie has a different studio,
without deferred faulting, during a fetch of twenty Movie objects,
twenty faults are created for the studio
relationship-one
fault for each movie. With deferred faulting, only one fault is
created-a deferred fault that is shared by all the movies.
Deferred faults have a special fault handler, which knows how to replace the deferred fault with a standard fault. Once the deferred fault is replaced with a normal fault, the normal faulting behavior applies.
In 4.5, EOGenericRecord enables deferred faulting; you get
the behavior without making any changes to existing code. Non-EOGenericRecord
enterprise object classes don't enable deferred faulting by default.
To enable it on a custom class, implement the class method useDeferredFaultCreation
to
return true
/YES
(the
default is false
/NO
).
Additionally, invoke the method willReadRelationship
before
accessing a relationship that might be a deferred fault. The willReadRelationship
method
allows the special fault handler to instantiate a normal fault before
it is accessed.
In Java programming, there's an additional benefit of deferred faulting: Deferred faulting allows you to have to-one relationships into an inheritance hierarchy. Without deferred faulting, a to-one relationship to a non-leaf entity is impossible without implementing workarounds (because of strong typing in the Java language). The workarounds are not necessary if you use deferred faulting. For more information on the inheritance limitation in Java and the workarounds, refer to the Enterprise Objects Framework Developer's Guide.
New API added to support the deferred faulting feature is summarized in this section.
New or Changed API | Description |
useDeferredFaultCreation |
A static/class method that defaults to false /NO . Override
to return true /YES on
your enterprise object class to use deferred fault creation.EOGenericRecord's implementation returns true /YES , indicating
that it uses the more efficient deferred fault technique.Note that in Java, this static method is not a formal part of the EODeferredFaulting interface because the Java language doesn't support the inclusion of static methods in an interface. It is, however, an informal part of the interface. A static method implemented in a custom enterprise object class will be invoked automatically to determine whether or not to use deferred fault creation. |
willReadRelationship (Java)willReadRelationship: (Objective-C) |
Invoke this before using any relationship in an enterprise
object that uses deferred fault creation. This method sets the corresponding
instance variable of the receiver using takeStoredValueForKey /takeStoredValue:forKey: .
Returns a newly instantiated fault if the object is a fault and
has a deferred fault handler. Returns the object otherwise. |
New or Changed API | Description |
createFaultForDeferredFault (Java) createFaultForDeferredFault:sourceObject: (Objective-C) |
Invoked by willReadRelationship to
ensure that a fault is valid. EOFaultHandler's implementation
simply returns its fault. |
Snapshot reference counting is a new feature that removes snapshots from an EODatabase when they are no longer used by any enterprise objects in an application. This feature reduces the memory footprint of WebObjects applications.
Note: Snapshot reference counting is not available in the client side of Java Client applications. The corresponding API is in the Java Client packages, but the snapshots are not released. |
The reference count on a snapshot is implicitly incremented when you create an enterprise object, either by fetching it in a batch or by faulting it in. An EOEditingContext decrements the reference count automatically when it forgets or refaults an enterprise object.
To support this feature, the method editingContextDidForgetObjectWithGlobalID
/ editingContext:didForgetObjectWithGlobalID:
has
been added to EOObjectStore. This method is not intended to be called
directly by your application.
As a developer you should not worry about this feature; it should just work without any additional code on your part. There are only a few cases where it could be incompatible with pre-EOF 4.5 applications:
null
/nil
.Sometimes you want a snapshot to stay around for the lifetime of your application. If you need this functionality there are three ways to force selected snapshots to stay around:
incrementSnapshotCountForGlobalID
on
EODatabase to force the snapshot to stay around. If you use this
approach, make sure to call decrementSnapshotCountForGlobalID
when
you don't need the snapshot anymore.You can turn the whole feature off and revert to the previous
behavior of retaining snapshots forever by invoking the class method disableSnapshotRefCounting
on EODatabase.
Make sure to call this method early in your application initialization
code, before the creation of any EODatabase instances.
The following tables summarize new or changed API to support the snapshot reference counting feature.
New or Changed API | Description |
incrementSnapshotCountForGlobalID (Java)incrementSnapshotCountForGlobalID: (Objective-C) |
If the receiver releases unreferenced snapshots, increments the reference count for the shared snapshot associated with the specified globalID. |
decrementSnapshotCountForGlobalID (Java)decrementSnapshotCountForGlobalID: (Objective-C) |
If the receiver releases unreferenced snapshots, decrements the reference count for shared snapshot associated with the specified globalID; if no more objects refer to the snapshot, removes it from the snapshot table. |
disableSnapshotRefCounting |
A static/class method that disables the snapshot reference counting feature so that instances don't release snapshots. |
New or Changed API | Description |
editingContextDidForgetObjectWithGlobalID (Java)editingContext:didForgetObjectWithGlobalID: (Objective-C) |
Invoked to inform the object store that it can stop keeping data about an object it passed to a child. Don't invoke this method; it is invoked automatically by the Framework. |
EOF caches database snapshots and uses the cached values to initialize objects. This significantly improves performance, since using the cached values is much faster than making round-trips to the database for fetches. However, this behavior can lead to staleness of the cached data; and it sometimes produces confusing results, especially when new values available from a fetch are ignored in favor of the stale snapshots.
A new snapshot timestamping feature updates snapshots appropriately
when fetching and allows an editing context to request that the
snapshots used to build enterprise objects are no older than the
editing context's fetchTimestamp
. The
default value for the fetchTimestamp
of
a new editing context is one hour earlier than the creation time
of the editing context. So any snapshots that are less than an hour
old are acceptable to the editing context; older cached values are
ignored. The default "lag" can be adjusted using the static method setDefaultFetchTimestampLag
(or
the corresponding Objective-C class method), and the fetchTimestamp
for
a specific editing context can be set directly with setFetchTimestamp
.
Note that the fetchTimestamp
is significant
only when fetching data (typically by sending objectsWithFetchSpecification
).
An existing enterprise object is unaffected by changes to the editing
context's fetchTimestamp
.
When an EODatabase records a snapshot, it now also records
a timestamp for that snapshot. The timestamp is an NSTimeInterval
(relative to the reference date as documented for the NSDate class).
Methods that return a snapshot from EODatabase or EODatabaseContext
now have variants that take an extra argument to specify a minimal timestamp
for the snapshot. If the recorded snapshot's timestamp is earlier
than the requested time, null
/nil
is
returned. If the snapshot is recent enough for the request, the snapshot
is returned as usual.
The following tables summarize new API added to support the snapshot timestamp feature.
Note: Support for snapshot timestamping is not available in the com.apple.client packages. However, since snapshots are maintained only on the server, no timestamping takes place on the client side of a Java Client application. In other words, this feature can be used to its fullest potential in a Java Client application. |
New or Changed API | Description |
DistantPastTimeInterval (Java)EODistantPastTimeInterval (Objective-C)(constant) |
The NSTimeInterval used as a lower bound on timestamps. |
setTimestampToNow |
Sets the internal timestamp to value returned by NSDate's timeIntervalSinceReferenceDate method. Used
for recording subsequent snapshots. |
snapshotForGlobalID(EOGlobalID) snapshotForGlobalID(EOGlobalID, double) (Java) |
The new, overloaded version of this method takes a double
argument to use as a timestamp. It returns the snapshot associated
with the specified globalID. Returns null if
there isn't a snapshot or if its timestamp is less than the specified
timestamp.The old version that only takes a globalID has been reimplemented to invoke the new version using DistantPastTimeInterval as
the timestamp. |
snapshotForSourceGlobalID(EOGlobalID, String)
(Java) |
The new, overloaded version of this method takes a double
argument to use as a timestamp. It returns the to-many snapshot
for the specified globalID and relationship name. Returns null if
there isn't a to-many snapshot or if the timestamp is less than
the specified timestamp.The old version that only takes a globalID and a String has been reimplemented to invoke the new version using DistantPastTimeInterval as
the timestamp. |
snapshotForGlobalID:after: (Objective-C) |
Returns the snapshot associated with the specified globalID.
Returns nil if there
isn't a snapshot or if its timestamp is less than the specified
timestamp. Note that snapshotForGlobalID: has
been reimplemented to invoke snapshotForGlobalID:after: with EODistantPastTimeInterval as
the timestamp. |
snapshotForSourceGlobalID:relationshipName:after: (Objective-C) |
Returns the to-many snapshot for the specified globalID and
relationship name. Returns nil if
there isn't a to-many snapshot or if the timestamp is less than
the specified timestamp. Note that snapshotForSourceGlobalID:relationshipName: has
been reimplemented to invoke snapshotForSourceGlobalID:relationshipName:after: with EODistantPastTimeInterval as
the timestamp. |
timestampForGlobalID (Java)timestampForGlobalID: (Objective-C) |
Returns the timestamp of the snapshot for the specified globalID.
Returns (EO)DistantPastTimeInterval if
there isn't a snapshot. |
timestampForSourceGlobalID (Java)timestampForSourceGlobalID:relationshipName: (Objective-C) |
Returns the timestamp of the to-many snapshot for the specified
globalID. Returns (EO)DistantPastTimeInterval if
there isn't a snapshot. |
New or Changed API | Description |
snapshotForGlobalID(EOGlobalID) snapshotForGlobalID(EOGlobalID, double) (Java) |
The new, overloaded version of this method takes a double
argument to use as a timestamp. It returns the snapshot associated
with the specified globalID. Returns null if
there isn't a snapshot or if its timestamp is less than the specified
timestamp. Searches first locally (in the transaction scope) and
then in the receiver's EODatabase.The old version that only takes a globalID has been reimplemented to invoke the new version using DistantPastTimeInterval as
the timestamp. |
snapshotForSourceGlobalID(EOGlobalID, String)
(Java) |
The new, overloaded version of this method takes a double
argument to use as a timestamp. It returns the to-many snapshot
for the specified globalID and relationship name. Returns null if
there isn't a to-many snapshot or if the timestamp is less than
the specified timestamp.The old version that only takes a globalID and a String has been reimplemented to invoke the new version using DistantPastTimeInterval as
the timestamp. |
snapshotForGlobalID:after: (Objective-C) |
Returns the snapshot associated with the specified globalID.
Returns nil if there
isn't a snapshot or if its timestamp is less than the specified
timestamp. Searches first locally (in the transaction scope) and
then in the receiver's EODatabase.Note that snapshotForGlobalID: has
been reimplemented to invoke snapshotForGlobalID:after: with EODistantPastTimeInterval as
the timestamp. |
snapshotForSourceGlobalID:relationshipName:after: (Objective-C) |
Returns the to-many snapshot for the specified globalID and
relationship name. Returns nil if
there isn't a to-many snapshot or if the timestamp is less than
the specified timestamp.Note that snapshotForSourceGlobalID:relationshipName: has
been reimplemented to invoke snapshotForSourceGlobalID:relationshipName:after: with EODistantPastTimeInterval as
the timestamp. |
New or Changed API | Description |
setDefaultFetchTimestampLag (Java)setDefaultFetchTimestampLag: (Objective-C) |
A static/class method that assigns the default timestamp
lag for new editing contexts. The default value is 3600.0 seconds
(one hour). When a new editing context is initialized, it is assigned a fetch timestamp equal to the current time less the default timestamp lag. Setting the lag too high might cause every new editing context to accept very old cached data. Setting the lag too low might degrade performance due to excessive fetching. A negative lag value is treated as 0.0. |
defaultFetchTimestampLag (Java)defaultFetchTimestampLag (Objective-C) |
A static/class method that returns the default timestamp lag. |
setFetchTimestamp (Java)setFetchTimestamp: (Objective-C) |
Sets the receiver's fetch timestamp. When an editing context
fetches objects from its parent object store, the parent object
store can use the timestamp to determine whether to use cached data
or to refetch the most current values. An editing context prefers
that fetched values are at least as recent as its fetch timestamp.
Note that the parent object store is free to ignore the timestamp;
so this value should be considered a hint or request and not a guarantee. Changing the fetch timestamp has no effect on existing objects in the editing context; it can affect only subsequent fetches. To refresh existing objects, invoke refaultObjects before you
invoke setFetchTimestamp .The initial value
for the fetch timestamp of a new non-nested editing context is the
current time less the defaultFetchTimestampLag .
A nested editing context always uses its parent's fetch timestamp. setFetchTimestamp raises
if it's invoked on a nested editing context. |
fetchTimestamp |
Returns the receiver's fetch timestamp. |
In previous versions of EOF, if a fault fired but no corresponding
database row could be found (for example because of a referential
integrity problem or because the row was deleted without EOF's
knowledge), the delegate method databaseContextFailedToFetchObject
/databaseContext:failedToFetchObject:globalID:
was
called. If the delegate didn't fix the problem, an exception was
raised immediately. In 4.5, The delegate is invoked, but the exception
is delayed or avoided, and an empty enterprise object is returned.
If the application later tries to save an object graph that requires
the missing fault, the exception is raised during saveChanges
.
If the object is never needed, no exception is raised.
The following tables summarize new API added to support the better handling of missing faults.
New or Changed API | Description |
missingObjectGlobalIDs |
Returns the globalIDs of any "missing" enterprise objects.
Returns an empty array if no missing objects are known to the receiver.
An object is "missing" when a fault fires and the corresponding
row for the fault isn't found in the database. To be notified when a missing object is discovered, implement the delegate method databaseContextFailedToFetchObject /databaseContext:failedToFetchObject:globalID: .If an application tries to save a missing object, an exception is raised. |
New or Changed API | Description |
databaseContextFailedToFetchObject (Java)databaseContext:failedToFetchObject:globalID: (Objective-C)(changed behavior) |
Invoked when a to-one fault can't find its data in
the database. Now if the method returns false /NO ,
the specified database context doesn't immediately raise as before.
Instead, it simply tracks the globalID of the offending object.
If the tracked globalID is in the list of updated objects when prepareForSaveWithCoordinator /prepareForSaveWithCoordinator:editingContext: is invoked
(saveChanges invokes this method), an exception
is raised. To get a list of the objects that failed to fetch, see the method missingObjectGlobalIDs . |
In EOF 4.5, a concrete adaptor can now implement methods that cause EOF to automatically attempt to reconnect to a database server when a connection is unexpectedly dropped. This behavior handles the problem of transient communication failures. By default reconnection is attempted by all of the adaptors that ship with EOF 4.5.
EOF now sends isDroppedConnectionException
to
the adaptor if an exception is raised during fetching or saving.
If the adaptor returns true
/YES
,
then it attempts to reconnect to the database and retry the operation.
(The adaptor context must also implement handleDroppedConnetion
to
clean up the state of the context and its channels before the reconnection
is attempted.) If the reconnection attempt fails, the exception
from the failure is raised as usual.
The delegate method reconnectionDictionaryForAdaptor
can
be used to provide a new connection dictionary for the reconnection
attempt. If the delegate is not implemented, the adaptor uses its
existing connection dictionary when reconnecting to the server.
You can completely override the database reconnection behavior
with the delegate method databaseContextShouldHandleDatabaseException
(Java)
or databaseContext: shouldHandleDatabaseException
(Objective-C).
For more information, see Table 5-20 .
The following tables summarize new API added to support the database reconnection feature.
New or Changed API | Description |
handleDroppedConnection |
The adaptor cleans up after a dropped connection by sending handleDroppedConnection to
all of its adaptor contexts and then clearing its array of contexts.If the receiver's delegate implements reconnectionDictionaryForAdaptor ,
that method is invoked and the result is used as the new connection dictionary
for the adaptor. Otherwise, the adaptor attempts new connections
using the original connection dictionary.You should never invoke this method; it is invoked automatically by the Framework. Subclasses don't normally need to override the superclass implementation. |
isDroppedConnectionException (Java)isDroppedConnectionException: (Objective-C) |
Returns true /YES if
the exception is one that the adaptor can attempt to recover from
by reconnecting to the database, false /NO otherwise.
The default implementation returns false /NO .
Subclasses should implement it to allow for automatic database reconnection. |
New or Changed API | Description |
reconnectionDictionaryForAdaptor (Java)reconnectionDictionaryForAdaptor: (Objective-C) |
Invoked from handleDroppedConnection .
If this method returns a non-null /nil value,
the value is used as the adaptor's new connection dictionary. The delegate is responsible for guaranteeing that the new connection dictionary is compatible with any EODatabase that is using the adaptor. If reconnection succeeds, the EODatabase continues to use its database snapshots as if nothing had happened. Therefore, the new database server should have the same data as the original. |
New or Changed API | Description |
handleDroppedConnection |
Implemented by subclasses to provide automatic database
reconnection support. If database reconnection is not supported,
subclasses don't have to implement it. Subclass implementations should clean up the state of the adaptor context and its associated adaptor channels so that they can be safely released and deallocated without any errors. Don't invoke this method; it's invoked automatically by the Framework. |
handleDroppedConnection |
Received when a dropped connection is detected to initiate
cleanup. It cleans up by sending handleDroppedConnection to
its adaptor, and then sending handleDroppedConnection to
all of its registered database contexts. When the cleanup procedure
is complete, the Framework can automatically reconnect to the database.Don't invoke this method; it's invoked automatically by the Framework. |
handleDroppedConnection |
Cleans up after a dropped connection by effectively releasing
adaptor context and database channels, and then creating a new adaptor
context. Don't invoke this method; it's invoked automatically by the Framework. |
databaseContextShouldHandleDatabaseException (Java)databaseContext:shouldHandleDatabaseException: (Objective-C) |
Invoked when an exception is thrown in response to a lost
database connection. Implement this method only if you want to override
the default reconnection behavior. If the delegate method is not
implemented, the reconnection decision is made according to the adaptor's
response to isDroppedConnectionException (isDroppedConnectionException: in
Objective-C).The implementation of this method should inspect the exception to determine if the exception is a response to a dropped connection. If not, the delegate should simply raise the specified exception. If the exception is in response to a dropped connection, the method can return true /YES to
allow the database context to handle the exception by automatically
reconnecting to the database or can return false /NO to
customize connection behavior.If the delegate returns false /NO ,
then the delegate is responsible for handling the exception and implementing
an appropriate reconnection strategy. The database context retries
the operation that generated the original exception without doing
any additional clean up and without attempting to reconnect to the
database. |
EOAdaptor, EOAdaptorContext, and EODatabaseContext now implement
the static method setDefaultDelegate
to
simplify the setting of delegates for new instances of those classes
(there are corresponding class methods in Objective-C). By default,
the default delegate for those classes is null
/nil
.
However, setDefaultDelegate
can be used
to establish a default delegate for a particular class that will
be assigned to any new instance of that class when the instance
is initialized.
The following tables summarize new API added to support the database reconnection feature.
New or Changed API | Description |
setDefaultDelegate (Java)setDefaultDelegate: (Objective-C) |
A static/class method that sets the default delegate for all newly created EOAdaptor instances. That is, specifies the object that is assigned as delegate to new adaptor objects. |
defaultDelegate |
A static/class method that returns the default delegate. |
New or Changed API | Description |
setDefaultDelegate (Java)setDefaultDelegate: (Objective-C) |
A static/class method that sets the default delegate for all newly created EOAdaptorContext instances (and their EOAdaptorChannels). That is, specifies the object that is assigned as delegate to new adaptor context objects and their channels. |
defaultDelegate |
A static/class method that returns the default delegate. |
New or Changed API | Description |
setDefaultDelegate (Java)setDefaultDelegate: (Objective-C) |
A static/class method that sets the default delegate for all newly created EODatabaseContext instances. That is, specifies the object that is assigned as delegate to new database context objects. |
defaultDelegate |
A static/class method that returns the default delegate. |
EOF 4.5 introduces two improvements to key-value coding: The addition of key binding objects and the enforcement of lowercase key names. The follow sections describe each.
New key-value coding primitives have been introduced. The new primitives are based on bindings, which associate a class/key pair to a mechanism for accessing the key. There are two types of bindings, get bindings and set bindings. They are represented by the new class EOKeyBinding.
To access an object's data with key-value coding, clients
typically use the EOKeyValueCoding and EOKeyValueCodingAdditions
methods valueForKey
, takeValueForKey
,
and so on. However, in EOF 4.5, clients can optimize access by obtaining and
caching bindings for particular class/key combinations and applying
those bindings directly. Classes can override the EOKeyValueCoding
methods (such as valueForKey)
directly,
but overriding keyValueBindingForKey
to
return an appropriately initialized binder object provides the maximum
performance benefit.
Note: The need to override the default key-value coding methods, particularly the new binding primitives, is extremely rare. The default behavior is very efficient and should be well suited to almost any application. |
Clients caching bindings are responsible for checking that the class of the object to which a binding is applied matches the target class of the binding. Using a binding obtained from one class on an object of another results in undefined behavior.
EOF expects keys to begin with a lowercase letter. It now
logs a warning if that restriction is violated. For backwards compatibility
with previous releases which did not strictly check capitalization,
you can use the EOKeyValueCoding.KeyBinding static method suppressCapitalizedKeyWarning
to
suppress the warning for capitalized keys (EOKeyBinding class method
in Objective-C). However, note that this method is deprecated
and will be removed in a future release.
The following new classes have been added to support key value bindings:
For more information, see the class specification for EOKeyValueCoding.KeyBinding/EOKeyBinding.
In addition, the EOKeyValueCoding interface/informal protocol has been enhanced to create and return key bindings. In Java, the new methods are defined in a new interface called EOKeyValueCoding.KeyBindingCreation. In Objective-C, the new methods are defined in EOKeyValueCoding.h. For more information, see the EOKeyValueCoding.KeyBindingCreation interface specification (Java) or the EOKeyBindingCreation informal protocol specification (Objective-C).
A new class, EOMultiReaderLock, provides EOF with recursive reader and writer locks. The locks are recursive; a single thread can request a lock many times, but a lock is actually taken only on the first request. Likewise, when a thread indicates it's finished with a lock, it takes an equal number of unlock calls to return the lock.
There is no limit on the number of reader locks that can be taken by a process. However, there can only be one writer lock at a time, and a writer lock is not issued until all reader locks are returned. (Reader locks aren't issued to new threads when there is a thread waiting for a writer lock, but threads that already have a reader lock can increment their lock count.)
Thread safety is maintained by using mutex locks (binary semaphores), which ensures that no more than one critical section of the class can be processed at a time. The queueing order of requests for writer locks is not managed by the class; the underlying implementation of mutex signaling manages the queue order.
EOMultiReaderLock correctly handles promotion of a read lock to a write lock, and the extension of a reader lock to the current writer. This prevents a thread from deadlocking on itself when requesting a combination of lock types.
EOMultiReaderLocks are slightly more time-expensive than NSRecursiveLocks because the recursion count has to be stored per-thread, causing each request for a reader lock to incur a hash. Writer locks are even more expensive because EOMultiReaderLock must poll the hashtable until all reader locks have been returned before the writer lock can be taken.
A new class, EOMultiReaderLock, has been added to the Framework to support the new multi reader and writer lock feature. For more information, see the corresponding class specification.
Note: This class doesn't exist in com.apple.client.eocontrol. Multithreaded clients aren't yet supported in Java Client applications. All the client-side locks in Java Client application's are no-ops. |
EOF 4.5 comes with a new sample adaptor: the LDAP adaptor. It provides read, modify, and delete access and limited support for inserting. Additionally it provides a simple way to verify a user's password on the Web with an LDAP server without requiring a model.
The LDAP adaptor is ready to use when you install WebObjects. The source code is provided so that you can use a different client library or enhance the adaptor yourself.
The LDAP adaptor consists of two pieces: The adaptor framework and an LDAP client library. Apple ships a client library based on the public University of Michigan LDAP Client. You can build and install this library as a framework, or you can substitute your own client library, such as the Netscape LDAP library. (The latter has not been tested, but both libraries conform to RFC 1823, the LDAP client API).
You create a model for an LDAP server with EOModeler the way you create models for other adaptors. Simply choose New from the Model menu, and choose LDAP as the adaptor for the new model.
Note: If all you are trying to do is authenticate users using an LDAP server's usernames and encrypted passwords, you don't need to create a model. See "Performing Authentication" . |
The LDAP adaptor defines the following connection keys, which are represented in the login panel:
The LDAP specification does not require LDAP servers to provide a means of learning the server's layout; providing a schema to clients is optional. For this reason, the LDAP adaptor might not be able to reverse-engineer your LDAP server to generate an EOModel automatically. If this is the case, you might need to create your model by hand.
Generally speaking, Netscape Directory Servers automatically create and provide schemas to clients. So, if you have a Netscape Directory server, you should be fine.
However, if the adaptor can't find subschema information,
it creates a default model with two entities: Person and NoSchemaDataAvailable.
If the server is ldap.bigfoot.com (a well known
server) and the scope is set to Subtree, this model works for finding
names. The NoSchemaDataAvailable entity is designed to be an error
message and should be deleted from the model. (EOAdaptors aren't
allowed to return null
/nil
when
reverse engineering a database, so the best alternative is to return
a minimal model.)
The LDAP adaptor provides limited support for adding entries to the server. If you plan to use the adaptor to insert entries, keep the following points in mind:
One of the common applications for LDAP is to verify a user's password on the Web. The authentication is generally done by the LDAP server, not by retrieving the user's password from an LDAP entry. So, in essence, all that is needed is a mutable connection dictionary from a model and a request to validate the connection. The LDAP Adaptor provides a simple way to do this without a model:
java.lang.Throwable athenticateUser()
or in Objective-C,
+ (NSException *)authenticateUserString:(NSString *)userString password:(NSString *)password withServer:(NSString *)server matchOnAttribute:(NSString *)searchAtt searchBase:(NSString *)base searchScope:(NSString *)scope;
The method is pretty easy to use and the header file contains
specifics on its use. Here is a sample code fragment from a WebObjects
application that has one page, "Main" with three instance variables: userName1
, password1
,
and isLoggedIn
. This
method is tied to the web page's Submit button.
- authenticateUser { NSException *exception; exception = [LDAPAdaptor authenticateUserString:userName1 password:password1 withServer:@"bigbird.apple.com" matchOnAttribute:@"cn" searchBase:@"o=apple computer" searchScope:@"Subtree"];ì if (exception) { NSLog(@"Auth failed."); isLoggedIn = NO; } else { NSLog(@"Auth successful."); isLoggedIn = YES; } return self; }
Or, in Java (isLoggedIn
is
a string instead of a BOOL in this example):
public WOComponent authenticateUser() { java.lang.Throwable ex = null; ex = LDAPAdaptor.authenticateUser ( userName, pswField, "bigbird.apple.com", "cn", "o=Apple Computer", "Subtree"); if (ex == null) { isLoggedIn = "You are now logged in."; } else { isLoggedIn = ex.getMessage(); } return this; }
This section summarizes other miscellaneous methods added in EOF 4.5 not covered in the other sections.
New or Changed API | Description |
hasOpenTransaction |
Returns true /YES if
a transaction is open (begun but not yet committed or rolled back).
For more information on this addition, see the section "Deprecated API" . |
New or Changed API | Description |
databaseContextWillFireObjectFaultForGlobalID (Java)databaseContext: (Objective-C) |
Invoked just before the Framework-generated fetch specification
(provided as an argument) is used to clear the fault for the specified
globalID. Note that it is very dangerous to modify the fetch specification. |
databaseContextWillFireArrayFaultForGlobalID (Java)databaseContext: (Objective-C) |
Invoked just before the Framework-generated fetch specification
(provided as an argument) is used to clear the fault for the specified
globalID and relationship. Note that it is very dangerous to modify the fetch specification. |
New or Changed API | Description |
createAndInsertInstanceOfEntityNamed: |
Creates a new enterprise object of the specified entity, inserts it into the receiving editing context, and returns the new object. |
New or Changed API | Description |
createAndInsertInstance |
Creates a new enterprise object of the specified entity, inserts it into the specified editing context, and returns the new object. |
New or Changed API | Description |
fetchSpecificationNamed (Java)fetchSpecificationNamed: (Objective-C) |
The receiver returns the fetch specification it associates with
the specified name. EOClassDescription's implementation returns null /nil ;
subclasses can override it to return a fetch specification. |
New or Changed API | Description |
fetchSpecificationNamed (Java) fetchSpecificationNamed:entityNamed: (Objective-C) |
A static/class method that returns the fetch specification that the specified entity associates with the specified fetch specification name. |
New or Changed API | Description |
evaluateWithObject (Java)evaluateWithObject: (Objective-C) |
Implemented by subclasses to return true /YES if
the provided object matches the criteria specified in the receiver, false /NO otherwise.
The argument should be an enterprise object, a snapshot dictionary,
or something that implements key-value coding. |
allQualifierKeys |
Returns an NSSet of strings, which are the left-hand sides
of all the qualifiers in the receiver. For example, if you have
a qualifier salary > 10000 AND manager.lastName = 'smith' allQualifierKeys returns
an array containing the strings "salary" and "manager.lastName".Subclasses should not override this method, instead they should override addQualifierKeysToSet . |
addQualifierKeysToSet (Java)addQualifierKeysToSet: (Objective-C) |
Adds the receiver's qualifier keys to the specified NSMutableSet.
The subclasses in the EOControl framework do this by traversing
the tree of qualifiers. Node qualifiers (such as EOAndQualifier)
recursively invoke this method until they reach a leaf qualifier (such
as EOKeyValueQualifier) which adds its key to the set. Subclasses of EOQualifier must implement this method. |
New or Changed API | Description |
assignGloballyUniqueBytes (Java
only) |
This method, which was not wrapped in 4.0, is the equivalent
of the Objective-C method, assignGloballyUniqueBytes: ,
which assigns a network-wide unique ID |
New or Changed API | Description |
isExplicitlyDisabled
(Java Client only)setExplicitlyDisabled
(Java Client only) |
Returns or sets whether or not the association is explicitly disabled. These methods are used by the new user interface generation layer, which is described in "Direct To Java Client" . An association is "explicitly disabled" when the display object shouldn't be editable, such as in the case where the display object simply displays the results of a search. |
New or Changed API | Description |
globalDefaultStringMatchOperator |
A static/class method that returns the default operator used
for matching strings, one of caseInsensitiveLike or like |
setGlobalDefaultStringMatchOperator (Java)setGlobalDefaultStringMatchOperator: (Objective-C) |
A static/class method that sets the default operator for instances to use for string matching. |
globalDefaultStringMatchFormat |
A static/class method that returns the default format used
for matching strings ("%@* ", for example). |
setGlobalDefaultStringMatchFormat (Java)setGlobalDefaultStringMatchFormat: (Objective-C) |
A static/class method that sets the default format for instances to use for string matching. |
globalDefaultForValidatesChangesImmediately |
A static/class method that returns true /YES if
instances validate immediately by default. |
setGlobalDefaultForValidatesChangesImmediately (Java)setGlobalDefaultForValidatesChangesImmediately: (Objective-C) |
A static/class method that sets the default validation behavior for instances. |
Nested transactions are no longer supported. EOF never actually used nested transactions. Furthermore, the concrete adaptors were not guaranteed to support them, especially since the SQL/92 standard doesn't allow nested transactions. New features in EOF 4.5 make nested transactions impossible to support.
Consequently, the following methods are deprecated.
Deprecated API | New API or Workaround |
canNestTransactions: |
None. No adaptor can nest transactions. |
transactionNestingLevel |
hasOpenTransaction Returns true /YES if
a transaction is open (begun but not yet committed or rolled back). |
For backwards compatibility, the Sybase Adaptor still allows you to attempt to begin a nested transaction, but the implementation ignores the nesting.